package com.jackstraw.jack_base.remote_command.config;

import cn.hutool.core.bean.BeanUtil;
import com.jackstraw.jack_base.remote_command.pool.SessionConnectionFactory;
import com.jackstraw.jack_base.remote_command.pool.SessionConnectionPool;
import com.jackstraw.jack_base.remote_command.pool.entity.SessiontConnectionConfig;
import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.remote_command.entity.JackSoftProperties;
import com.jackstraw.jack_base.util.SpringUtil;
import lombok.Data;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.Environment;

import java.util.HashMap;
import java.util.Map;

@Data
@Configuration
public class JschConfig implements InitializingBean, DisposableBean {

    @Autowired
    private SessiontConnectionConfig sessiontConnectionConfig;

    @Autowired
    private JackSoftProperties jackSoftProperties;

    @Autowired
    private Environment environment;

    private Map<String, JackSoftProperties.SoftProperties> jackSoftPropertiesMap = new HashMap<>();

    private Map<String, Map<String, String>> jackDictPropertiesMap = new HashMap<>();

    private Map<String, String> jackDictPropertiesPublicMap = new HashMap<>();

    private Map<String, SessiontConnectionConfig> sessiontConnectionConfigMap;

    private GenericApplicationContext genericApplicationContext;

    private ConfigurableApplicationContext applicationContext;


    public JschConfig(ApplicationContext applicationContext) {
        SpringUtil.setApplicationContextJack(applicationContext);
        this.applicationContext = (ConfigurableApplicationContext) applicationContext;
        this.genericApplicationContext = (GenericApplicationContext) applicationContext;
    }

    public void logout(SessiontConnectionConfig sessiontConnectionConfig) {
        this.logout(sessiontConnectionConfig.getConnectName());
    }


    public void logout(String connName) {
        String sessionPoolName = SessiontConnectionConfig.getSessionPoolName(connName);
        SessionConnectionPool sessionConnectionPool = SpringUtil.getBean(sessionPoolName, SessionConnectionPool.class);
        sessionConnectionPool.getSessionGenericObjectPool().close();
        genericApplicationContext.removeBeanDefinition(sessionPoolName);
        sessionConnectionPool = null;
    }


    public void login(SessiontConnectionConfig sessiontConnectionConfig) {
        if (sessiontConnectionConfig.getEnable()) {
            //说明该配置为启用状态
            SessionConnectionFactory sessionConnectionFactory
                    = new SessionConnectionFactory(sessiontConnectionConfig);
            SessionConnectionPool sessionConnectionPool
                    = new SessionConnectionPool(sessionConnectionFactory);
            genericApplicationContext.registerBean(
                    SessiontConnectionConfig.getSessionPoolName(sessiontConnectionConfig.getConnectName()),
                    SessionConnectionPool.class, () -> sessionConnectionPool);

            if (StringUtil.StringUtilsBylang3.isNotEmpty(sessiontConnectionConfig.getRootPassword())) {
                SessiontConnectionConfig sessiontConnectionConfigByRoot = new SessiontConnectionConfig();
                BeanUtil.copyProperties(sessiontConnectionConfig, sessiontConnectionConfigByRoot);
                sessiontConnectionConfigByRoot.setUserName(SessiontConnectionConfig.DEFAULT_USER_NAME);
                sessiontConnectionConfigByRoot.setPassword(sessiontConnectionConfig.getRootPassword());
                sessiontConnectionConfigByRoot.setConnectName(SessiontConnectionConfig.getRootConnName(sessionConnectionPool.getConnName()));
                SessionConnectionFactory sessionConnectionFactoryByRoot
                        = new SessionConnectionFactory(sessiontConnectionConfigByRoot);
                SessionConnectionPool sessionConnectionPoolByRoot
                        = new SessionConnectionPool(sessionConnectionFactoryByRoot);
                genericApplicationContext.registerBean(
                        SessiontConnectionConfig.getSessionPoolNameByRoot(sessiontConnectionConfig.getConnectName()),
                        SessionConnectionPool.class, () -> sessionConnectionPoolByRoot);
            }

        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.setJackSoftPropertiesMap(jackSoftProperties.getJackSoftPropertiesMap());
        if (ObjectUtils.isNotEmpty(this.getSessiontConnectionConfig())) {
            this.setSessiontConnectionConfigMap(this.getSessiontConnectionConfig().resolverProperties());
            this.getSessiontConnectionConfig().setServicePropertiesMap(this.getSessiontConnectionConfigMap());
            this.getSessiontConnectionConfigMap().values().stream().forEach(this::login);
        }
        this.setJackDictPropertiesPublicMap(this.getSessiontConnectionConfig().getJackDictPropertiesPublicMap());
        this.setJackDictPropertiesMap(this.getSessiontConnectionConfig().getJackDictPropertiesMap());
    }


    @Override
    public void destroy() throws Exception {
        Map<String, SessionConnectionPool> beansOfType = SpringUtil.getBeansOfType(SessionConnectionPool.class);
        beansOfType.values().stream().forEach(sessionConnectionPool -> {
            logout(sessionConnectionPool.getConnName());
        });
        beansOfType.clear();
        beansOfType = null;
    }
}
